//////////////////////////////////////////////////////////////////////////
//   File Name: bkcolor.h
// Description: HLS & RGB processor
//     Creator: Zhang Xiaoxuan
//     Version: 2009.6.10 - 1.0 - Create
//////////////////////////////////////////////////////////////////////////

#include "duistd.h"
#include "duicolor.h"


namespace DuiEngine
{

DuiColor::DuiColor()
    : red(0)
    , green(0)
    , blue(0)
    , lightness(0)
    , saturation(0)
    , hue(0)
{
}

DuiColor::DuiColor(double h, double l, double s)
{
    hue		   = h;
    lightness  = l;
    saturation = s;

    ToRGB();
}

DuiColor::DuiColor (BYTE r, BYTE g, BYTE b)
{
    red   = r;
    green = g;
    blue  = b;

    ToHLS();
}

DuiColor::DuiColor(COLORREF color)
{
    red   = GetRValue(color);
    green = GetGValue(color);
    blue  = GetBValue(color);

    ToHLS();
}

// lightness  [0..1]
// saturation [0..1]
// hue		  [0..360)
void DuiColor::ToHLS(void)
{
    double mn, mx;
    int	   major;

    if ( red < green )
    {
        mn = red;
        mx = green;
        major = Green;
    }
    else
    {
        mn = green;
        mx = red;
        major = Red;
    }

    if ( blue < mn )
        mn = blue;
    else if ( blue > mx )
    {
        mx = blue;
        major = Blue;
    }

    if ( mn==mx )
    {
        lightness    = mn/255;
        saturation   = 0;
        hue          = 0;
    }
    else
    {
        lightness = (mn+mx) / 510;

        if ( lightness <= 0.5 )
            saturation = (mx-mn) / (mn+mx);
        else
            saturation = (mx-mn) / (510-mn-mx);

        switch ( major )
        {
        case Red  :
            hue = (green-blue) * 60 / (mx-mn) + 360;
            break;
        case Green:
            hue = (blue-red) * 60  / (mx-mn) + 120;
            break;
        case Blue :
            hue = (red-green) * 60 / (mx-mn) + 240;
        }

        if (hue >= 360)
            hue = hue - 360;
    }
}

void DuiColor::ToRGB(void)
{
    // lightness  [0..1]
    // saturation [0..1]
    // hue		  [0..360)

    lightness = max(0, min(1, lightness));
    saturation = max(0, min(1, saturation));
    hue = max(0, min(360, hue));
    if (360 == hue)
        hue = 0;

    if (saturation == 0)
    {
        red = green = blue = (unsigned char) (lightness*255);
    }
    else
    {
        double m1, m2;

        if ( lightness <= 0.5 )
            m2 = lightness + lightness * saturation;
        else
            m2 = lightness + saturation - lightness * saturation;

        m1 = 2 * lightness - m2;

        red   = _Value(m1, m2, hue + 120);
        green = _Value(m1, m2, hue);
        blue  = _Value(m1, m2, hue - 120);
    }
}

DuiColor::operator COLORREF() const throw()
{
    return RGB(red, green, blue);
}


unsigned char DuiColor::_Value(double m1, double m2, double h)
{
    while (h >= 360) h -= 360;
    while (h <    0) h += 360;

    if (h < 60)
        m1 = m1 + (m2 - m1) * h / 60;
    else if (h < 180)
        m1 = m2;
    else if (h < 240)
        m1 = m1 + (m2 - m1) * (240 - h) / 60;

    return (unsigned char)(m1 * 255);
}

}//end